package gateway

import (
	"github.com/Unixeno/TheMoon/planet"
	"github.com/Unixeno/TheMoon/planet/orm/event"
	"github.com/Unixeno/TheMoon/planet/orm/model"
	"github.com/Unixeno/TheMoon/planet/orm/moon"
	"github.com/Unixeno/TheMoon/planet/orm/zone"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/mem"
	"net/http"
	"os"
	"runtime"
	"strconv"
)

// Moon 信息列表
//
// swagger:response EventList
type EventList struct {
	// in:body
	Body []model.Event
}

// swagger:parameters ListEvents
type ListEventsReq struct {
	// 消息数量
	// in:query
	Nums int `json:"nums"`
	// 消息等级，当前只能为error
	// in:query
	Level string `json:"level"`
	// MoonID
	// in:query
	MoonID string `json:"moon_id"`
	// source
	// in:query
	Source string `json:"source"`
}

// swagger:route GET /events System ListEvents
//
// ListEvents
//
// 返回节点事件
//
//     Responses:
//       200: EventList
//       500: body:ErrorResponse
func ListEvents(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	nums := 0
	if query.Get("nums") != "" {
		nums, _ = strconv.Atoi(query.Get("nums"))
	}
	logger.Debugf("fetch %d events", nums)
	dao := event.New()

	dao.Source = query.Get("source")
	dao.MoonID = query.Get("moon_id")
	dao.Level = model.LevelDebug // todo: 支持自定义事件类型

	events, err := dao.List(nums)
	if err != nil {
		logger.WithError(err).Error("failed to get events")
		return
	}
	WriteResponse(w, events)
}

// System Version
//
// swagger:response SystemVersion
type VersionInfoResp struct {
	// in: body
	Body VersionInfo
}

type VersionInfo struct {
	// API版本
	ApiVersion string
	// Planet版本
	PlanetVersion string
	// 构建时间
	BuildTime string
	// CPU架构
	OSArch string
	// go编译版本
	GoVersion string
	// 代码git提交版本
	GitCommit string
	// 内核版本
	KernelVersion string
}

// swagger:route GET /version System Version
//
// Version
//
// 获取系统版本信息
//
//     Responses:
//       200: SystemVersion
func Version(w http.ResponseWriter, r *http.Request) {
	WriteResponse(w, VersionInfo{
		ApiVersion:    APIVersion,
		PlanetVersion: planet.Version,
		BuildTime:     planet.BuildTime,
		OSArch:        planet.OSArch,
		GoVersion:     planet.GoVersion,
		GitCommit:     planet.GitCommit,
	})
}

// System Statistics Information
//
// swagger:response SystemStats
type StatsResp struct {
	// in: body
	Body SystemStatsInfo
}

type SystemStatsInfo struct {
	// 当前节点数量
	TotalMoons int
	// 当前在线的节点数量
	ActiveMoons int
	// 区域数量
	Zones int
	// 操作系统
	OS     string
	Kernel string
	// CPU架构
	Architecture string
	// CPU型号
	CPU string
	// CPU核心数
	Cores int
	// 总内存
	TotalMemory uint64
	// 可用内存
	AvailableMemory uint64
	// 启动时间
	Uptime uint64
	// 主机名
	Hostname string
	// 数据库类型
	SQLBackend string
	// GC 计数
	GCCount uint32
	// 堆内对象计数
	HeapObjects uint64
	// 堆内存使用量
	HeapMem uint64
	// 栈内存使用量
	StackMem uint64
	// 程序内存使用量
	MemoryUsage uint64
}

// swagger:route GET /stats System SystemStats
//
// SystemStats
//
// 获取系统统计信息
//
//     Responses:
//       200: SystemStats
func SystemStats(w http.ResponseWriter, r *http.Request) {
	moonDao := moon.New()
	zoneDao := zone.New()

	cpuInfo, _ := cpu.Info()
	cpuCount, _ := cpu.Counts(true)

	kernelVersion, _ := host.KernelVersion()
	platform, _, version, _ := host.PlatformInformation()
	hostname, _ := os.Hostname()

	memoryStats, _ := mem.VirtualMemory()
	uptime, _ := host.Uptime()

	stats := &runtime.MemStats{}
	runtime.ReadMemStats(stats)

	WriteResponse(w, SystemStatsInfo{
		TotalMoons:      moonDao.Count(model.MoonAllState),
		ActiveMoons:     moonDao.Count(model.MoonConnected),
		Zones:           zoneDao.Count(),
		OS:              platform + " " + version,
		Kernel:          kernelVersion,
		Architecture:    runtime.GOARCH,
		CPU:             cpuInfo[0].ModelName,
		Cores:           cpuCount,
		TotalMemory:     memoryStats.Total,
		AvailableMemory: memoryStats.Available,
		Uptime:          uptime,
		Hostname:        hostname,
		SQLBackend:      "sqlite",
		GCCount:         stats.NumGC,
		HeapObjects:     stats.HeapObjects,
		HeapMem:         stats.HeapAlloc,
		StackMem:        stats.StackInuse,
		MemoryUsage:     stats.HeapInuse,
	})
}
